package main;

import com.backblaze.erasure.fec.Snmp;
import com.google.protobuf.MessageLite;
import io.netty.buffer.ByteBuf;
import kcp.ChannelConfig;
import kcp.KcpListener;
import kcp.KcpServer;
import kcp.Ukcp;
import main.bean.Message;
import main.bean.Player;
import main.bean.Room;
import main.handler.FightMessageHandler;
import main.handler.HeartBeatHandler;
import main.handler.JoinRoomHandler;
import main.service.GameCache;
import main.service.HandlerManager;
import main.service.IHandler;
import main.service.PBMessageManager;
import threadPool.thread.DisruptorExecutorPool;

/**
 * Created by JinMiao
 * 2019-07-24.
 */
public class ServerMain implements KcpListener {

    private GameCache gameCache = new GameCache();

    private PBMessageManager pbMessageManager = new PBMessageManager();

    private HandlerManager handlerManager = new HandlerManager();


    public static void main(String[] args) {

        ServerMain serverMain = new ServerMain();

        serverMain.init();

        ChannelConfig channelConfig = new ChannelConfig();
        channelConfig.setFastresend(2);
        channelConfig.setSndwnd(300);
        channelConfig.setRcvwnd(300);
        channelConfig.setMtu(500);

        channelConfig.setAckNoDelay(true);
        channelConfig.setInterval(40);
        channelConfig.setNocwnd(true);
        channelConfig.setTimeoutMillis(10000);
        channelConfig.setAutoSetConv(true);

        //channelConfig.setFecDataShardCount(10);
        //channelConfig.setFecParityShardCount(3);
        channelConfig.setCrc32Check(false);


        KcpServer kcpServer = new KcpServer();
        kcpServer.init(1, serverMain, channelConfig, 18888);

        for (int i = 0; i < 1; i++) {
            serverMain.gameCache.disruptorExecutorPool.createDisruptorProcessor("logic-" + i);
        }

        DisruptorExecutorPool.scheduleWithFixedDelay(() -> {
            System.out.println("每秒收包" + (Snmp.snmp.InBytes.longValue() / 1024.0 / 1024.0 * 8.0) + " M");
            System.out.println("每秒发包" + (Snmp.snmp.OutBytes.longValue() / 1024.0 / 1024.0 * 8.0) + " M");
            System.out.println();
            Snmp.snmp = new Snmp();
        }, 1000);
    }

    private void init(){
        addHandler(new HeartBeatHandler());
        addHandler(new JoinRoomHandler());
        addHandler(new FightMessageHandler());
    }


    private void addHandler(IHandler iHandler){
        handlerManager.addHandler(iHandler.messageId(),iHandler);
        if(iHandler.initBodyClass()!=null){
            pbMessageManager.addMessageCla(iHandler.messageId(),iHandler.initBodyClass());
        }
    }





    @Override
    public void onConnected(Ukcp ukcp) {
        System.out.println("有连接进来"+ukcp.user());
        Player player = new Player(ukcp);
        ukcp.user().setCache(player);
        //joinRoom(player);
    }

    @Override
    public void handleReceive(ByteBuf byteBuf, Ukcp ukcp)  {
        int messageId = byteBuf.readShort();
        byte encryption = byteBuf.readByte();
        int bodyLenth = byteBuf.readableBytes();


        Message message = new Message();
        message.setActionId(messageId);

        if(bodyLenth!=0){
            byte[] bodybytes = new byte[bodyLenth];
            byteBuf.readBytes(bodybytes);
            MessageLite messageLite= pbMessageManager.getMessage(messageId,bodybytes);
            message.setBody(messageLite);
        }

        Player player = ukcp.user().getCache();

        Room room = gameCache.playerRooms.get(player.getId());
        IHandler iHandler = handlerManager.getHandler(messageId);
        if(room!=null){
            room.getiMessageExecutor().execute(() -> {
                try {
                    iHandler.handler(player,message,gameCache);
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                }
            });
            return;
        }
        try {
            iHandler.handler(player,message,gameCache);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

        System.out.println("收到数据包");

    }

    @Override
    public void handleException(Throwable ex, Ukcp ukcp) {
        ex.printStackTrace();
    }

    @Override
    public void handleClose(Ukcp ukcp) {
        Player player = ukcp.user().getCache();
        Room room = gameCache.playerRooms.remove(player.getId());
        room.getPlayers().remove(player.getId());

        System.out.println("连接断开了"+ukcp.user().getRemoteAddress());
    }
}